EventBridgeのターゲットに指定したSaaSのAPIがスロットリングしないようにできるか呼び出し速度を調整して挙動を確認してみた
どうも!オペレーション部の西村祐二です。
以前、下記のようなブログを書きました。
LambdaなしでSaaSと連携できかつAPI呼び出し時にセキュアにすることも可能なためとても可能性を感じています。
SaaSのAPIをリクエストする上で気にすることのひとつとしてAPIのレートリミットがあるかと思います。
EventBridgeには外部APIに対してリクエストする際に呼び出し速度を調整する機能があります。
今回その機能を試してSaaSのAPI今回はAuth0のManagement APIがスロットリングしないように調整できるか、どのような挙動をするのか確認してみたいと思います。
結論:試してわかったこと(2021/09/16現在)
はじめに結論から述べると下記のことがわかりました。
- EventBridgeのリトライ設定(デフォルトで設定されている設定)により、スロットリングしても時間をあけてSaaS側にイベントが飛んでくる
-
EventBridgeのルール設定のCloudWatchメトリクスでわかる情報が少ない(2021/09/16現在)
-
順序保証はされない(滞留している過去のイベントが飛んでくることもありえそう)
-
呼び出し速度で設定した値の間隔でAPIがリクエストされるわけではない
-
呼び出し速度を低く設定することでSaaS APIのスロットリングの可能性を減らすことはできそうだが、遅延が発生するので要検証
-
デフォルトのリトライ設定で(遅延してイベントが届いても)システム的に問題ないか確認する必要がありそう
-
デフォルトのリトライ設定のイベント保持期間、リトライ回数を減らし、エラーになったイベントはDLQに流しハンドリングするようにしたほうが扱いやすい場面がありそう
Auth0 Management APIのレートリミット
今回、利用するSaaSのAPIとしてAuth0 Management APIを利用します。
レートリミットについてのページは下記になります。
翻訳をかけたページのキャプチャです。今回、無料版のアカウントを利用するため、1秒あたりのリクエスト数10、1分あたりのバースト120になります。
動作確認用のスクリプト
EventBridgeのイベントバスに対して100個のイベントを発行するpythonスクリプトを用意しました。
指定したAuth0ユーザのメタデータを更新するイベントを発行します。
前提として下記ブログのAuth0に対してイベント発行できる前提で進めていきます。
import time import json import urllib.parse import boto3 EVENT_BUS = 'default' events = boto3.client('events') def get_payload(count): eventDetail = { "id": urllib.parse.quote("google-oauth2|000000000000000"), "user_metadata": { str(count): "test" } } return { 'EventBusName': EVENT_BUS, 'Detail': json.dumps(eventDetail), 'DetailType': 'myDetailType', 'Source': 'com.mycompany.myapp' } def put_events(payload): res = events.put_events( Entries=payload ) print(res) def finish(count): print(f"!Finish! count: {count}") def main(): count = 0 try: while count < 100: time.sleep(0.1) payload = get_payload(count) put_events([payload]) count += 1 finally: finish(count) if __name__ == "__main__": main()
スクリプトの簡単な説明をします。
- get_payload()
発行するイベントの内容を取得します。 キーにcountを設定しているのは、Auth0ユーザーのメタデータを更新するさいの挙動として、全て上書きではなくキーがなければ追加、あれば上書きする挙動になっており、イベントの欠損がないか確認しやすくするために、keyにcountを指定しています。
- put_events()
イベントバスに対してイベントを発行します。
- finish()
処理終了時にログを出力するための処理です。
- main()
1イベントに1つのペイロードを含めたイベントを0.1秒ごとに100個発行するための処理です。
呼び出し速度(300/秒)のときの挙動
EventBridgeの外部API呼び出し(API destinations)の設定は下記のような状態でスクリプトを実行します。
デフォルトでは呼び出し速度300となっています。
先程記した100個のイベントを出力するスクリプトを実行します。
python run.py
Auth0のログを確認
ログには想定通りリミット制限に引っかかったログが出力されていました。
ユーザのメタデータも歯抜けの状態となっておりました。
ただ、時間をあけて再度ログを確認するとユーザのメタデータを更新した旨のログが確認されました。
そして、20分程度かかって最終的にはすべてのイベントが処理されました。
CloudWatchのメトリクスをみてみる
メトリクスからリトライされているか情報は確認できない?ようでした。
なぜ、遅れてイベントが届いたのか?
EventBridgeのターゲットに対するリトライ設定がデフォルト、イベントの送信を24時間保持し、最大185回再試行する設定となっているからでした。
イベントの再試行ポリシーとデッドレターキューの使用 - Amazon EventBridge
呼び出し速度(1/秒)のときの挙動
今度は呼び出し速度を1にして動作確認してみます。
Auth0ユーザのメタデータをclearして再度スクリプトを実行します。
python run.py
Auth0のログ
1秒間隔ではなく複数のイベントが一気に届いているようでした。
しかし、後続の第2派のイベントが届くまで時間がかかりました。約5分後
この、「間隔をあけて複数のイベント届く」を繰り返しAPIのスロットリングが発生することはありませんでした。
ただ、はじめのイベントのログが届いてから、100個のイベントが届くまで約20分ほどかかっていました。
"date": "2021-09-16T14:40:29.824Z", // はじめに届いたイベントの時刻 . . . "date": "2021-09-16T15:01:05.608Z", // 最後に届いたイベントの時刻
結果としては、スロットリングはしませんでしたが、呼び出し速度に設定した値でリクエストが送信されるわけではなく、発行した100個のイベントがすべて届くまでかなりの時間かかりました。
試してみてわかったこと(2021/09/16現在)
繰り返しになりますが、試してみてわかったこと、所感を下記にまとめます。
- EventBridgeのリトライ設定(デフォルトで設定されている設定)により、スロットリングしても時間をあけてSaaS側にイベントが飛んでくる
-
EventBridgeのルール設定のCloudWatchメトリクスでわかる情報が少ない(2021/09/16現在)
-
順序保証はされない(滞留している過去のイベントが飛んでくることもありえそう)
-
呼び出し速度で設定した値の間隔でAPIがリクエストされるわけではない
-
呼び出し速度を低く設定することでSaaS APIのスロットリングの可能性を減らすことはできそうだが、遅延が発生するので要検証
-
デフォルトのリトライ設定で(遅延してイベントが届いても)システム的に問題ないか確認する必要がありそう
-
デフォルトのリトライ設定のイベント保持期間、リトライ回数を減らし、エラーになったイベントはDLQに流しハンドリングするようにしたほうが扱いやすい場面がありそう
さいごに
EventBridgeのターゲットに指定したSaaSのAPIがスロットリングしないようにできるか呼び出し速度を調整して挙動を確認してみました。
結論としてはスロットリングの可能性を低くすることはできるが、想定した挙動とは違った挙動をしていたので、実際に利用する際には検証が必要かと思います。
今回、想定したイベントが、1イベントに1つのペイロードを含めたものだったので、
複数のペイロードを含めた場合はどうなるのか、リトライ設定を変更したときの挙動はどうなるのか
余裕があれば追加検証してみたいと思います。
誰かの参考になれば幸いです。